package org.example.shop.web;

import lombok.extern.slf4j.Slf4j;
import org.example.shop.service.GoodsService;
import org.example.shop.util.AppConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.concurrent.ConcurrentHashMap;

@RestController
@Slf4j
public class GoodsController {
    private GoodsService goodsService;

    @Autowired
    public void setGoodsService(GoodsService goodsService) {
        this.goodsService = goodsService;
    }

    // 一开始应该把秒杀的商品数据放缓存
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    //初始化缓存数据
    @PostConstruct // 对应controller的void方法只调用一次
    public void initCacheData() {
        goodsService.findAll().forEach(g -> {
            log.info("对 {} 进行缓存 库存为 {}", g.getName(), g.getStock());
            // 对商品库存进行缓存
            stringRedisTemplate.opsForValue().set(AppConstants.GOODS_STOCK_KEY + g.getId(),
                    g.getStock().toString());
        });
    }

    // 存储已经卖完的商品信息
    private static ConcurrentHashMap<Integer,Boolean> stockOutMap = new ConcurrentHashMap<>();


    @RequestMapping("/kill/{id}")
    public String secKill(@PathVariable("id") Integer id) {
        // 分布式锁
        if(stockOutMap.get(id) != null){
            return "fail: 内存说已经卖完了";
        }


        String cacheKey = AppConstants.GOODS_STOCK_KEY + id;
//         对应redis的数据进行jian - 1，并返回减法后的结果
        long count = stringRedisTemplate.opsForValue().decrement(cacheKey);
        if (count < 0) {
            // 此时库存没有了 , 保存到已买完的对象
            stockOutMap.put(id,true);
            log.info("stock count ===>" + count);
            // 对缓存进行库存 + 1
            stringRedisTemplate.opsForValue().increment(cacheKey); //
            return "fail:缓存说库存不足";
        }


        try {
            Integer orderId = goodsService.secKill(id, 1);
            if (orderId == null || orderId < 1) {
                return "fail";
            } else {
                return "success";
            }
        } catch (Exception e) {
            //如果数据库下单失败 则 需要对缓存进行还原
            stringRedisTemplate.opsForValue().increment(cacheKey); //
            return "秒杀失败:" + e.getMessage();
        }
    }
}
